<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/5/14 0014
 * Time: 下午 3:35
 */

namespace App\Enum;

use App\Common\AuthCommon;
use App\Utility\BaseEnum;
use App\Common\BaseComm;


/**
 * 三公的配置参数分类,用到通用棋牌枚举类CardEnum类成员变量和方法直接引入即可
 * 保存当前棋牌的说明数据
 * @author XCH
 *
 */
class SanggEnum
{
    /**
     * 三公不同于抢庄牛牛的牌型等级
     * @var int
     */
    const GAME_SANGG_LEVEL = [
        0 => ['name' => '零点','level' => 0,'mutle'=>1],
        1 => ['name' => '一点','level' => 1,'mutle'=>1],
        2 => ['name' => '两点','level' => 2,'mutle'=>1],
        3 => ['name' => '三点','level' => 3,'mutle'=>1],
        4 => ['name' => '四点','level' => 4,'mutle'=>1],
        5 => ['name' => '五点','level' => 5,'mutle'=>1],
        6 => ['name' => '六点','level' => 6,'mutle'=>1],
        7 => ['name' => '七点','level' => 7,'mutle'=>2],
        8 => ['name' => '八点','level' => 8,'mutle'=>2],
        9 => ['name' => '九点','level' => 9,'mutle'=>2],
        10 => ['name' => '三公','level' => 10,'mutle'=>3],
        11 => ['name' => '炸弹','level' => 11,'mutle'=>4],
        12 => ['name' => '爆玖','level' => 12,'mutle'=>5],
    ];

    /**
     * 生成牌规则
     * 游戏一、 抢庄牛牛
        ?  如：值为 360c2c1418 0000000000 360c2c1418 0000000000 1
        ? 字段规则第一位是花色，第二位数是牌值，第三位是花色，第四位数是牌值，以此类推
        ? 每个玩家 5 张手牌共占 10 位，依次为 1-4 号座位的玩家
        ? 最后面一位表示庄家的座位号,1-4 分别对应 1-4 号位
        ? 字符与花色对应关系、字符与牌值对应关系同德州扑克
        ? 例： 值为：360c2c14180000000000360c2c141800000000001 表示：1 号位玩家手牌♠6♦Q♥ Q♣4♣8；2 号位没有玩家；3 号位玩家手牌♠6♦Q♥Q♣4♣8；4 号位没有玩家；庄家是 1号位的玩家
     */
    public static function createRoomGameSANGG($playerNum,$param = FALSE,$sigle = false) {
        $everyCard = 3; //每人3张牌
        if(!$playerNum || !$everyCard || intval($everyCard) > 10 ) return false ;
        $fullCards = CardEnum::getFullCards(false); //牌的数据；
        //echo json_encode($fullCards);exit ;
        $fullCards = !empty($fullCards) ? array_column($fullCards, null,'key') : false ;
        $allCards = !empty($fullCards) ? array_column($fullCards,'key') : false ; //所有牌值；
        @shuffle($allCards);    //洗牌；
        $useCards = $lastUserCards =  [];
        $useCardsName = [];
        $valIndex = 0 ;                      //每个玩家取5张牌；
        foreach ($allCards as $r => $paval){ //牌值；
            $thisYl = $valIndex % $playerNum;
            $pinfo = isset($fullCards[$paval])? $fullCards[$paval] :false ;
            if (isset($pinfo) && !empty($pinfo)) {
                //把玩家对应位置的牌值加上去；
                $oneUscard = isset($useCards[$thisYl]) ? $useCards[$thisYl] : [];
                if(empty($oneUscard) || (!empty($oneUscard) && sizeof($oneUscard) < $everyCard)){
                    $useCards[$thisYl][] = $paval;  //把玩家位置的值带上；
                    $useCardsName[$thisYl][] = isset($pinfo["name"]) ? $pinfo["name"] : "";     //牌值；
                }
                $valIndex ++;
            }
        }
        if(!$useCards) return false ;   //牌的数据；
        foreach ($useCards as $pr => $pkey) {
            $pailist = [];
            $paiarr = isset($useCardsName[$pr]) ? $useCardsName[$pr]: false ;
            if(isset($pkey) && !empty($pkey) && !empty($paiarr)){
                $sort1 = [];//按牌值和花色排序
                $sort2 = [];
                foreach ($pkey as $r => $val){  //配置数据
                    $huaval = CardEnum::getCardHua($val);   //花色
                    $dottval = $dott_text = CardEnum::getCardDott($val);  //计算单个值的点数
                    if(isset($val) && $huaval != 4 && $dottval > 10 ){  $dottval = 0 ;  }
                    $pailist[] = ['key'=>$val,"name"=> isset($paiarr[$r]) ? $paiarr[$r]: "", "dott" => $dottval,"t_dot" =>$dott_text ];
                    $sort1[] = $dott_text;
                    $sort2[] = $val;
                }
                array_multisort($sort1,SORT_DESC,$sort2,SORT_DESC,$pailist);
                //$valIndex = $pr + 1;            //取位置内容；
                $lastUserCards[$pr] = array_column($pailist,'key');
            }
        }
        return $lastUserCards;
    }
    
    
    //获取牛的点数
    protected static function getNiuDottod($notnums,&$jqk_num = 0,& $keyvalues = false) {
        $resList = [];
        $allNumVals = CardEnum::CARD_NUMS;
        $wangArr = array(CardEnum::CARD_BIGG_W,CardEnum::CARD_SMALL_W);
        foreach ($notnums as $n => $numstr){
            if(in_array($numstr, $wangArr))continue ;   //没有王；
            $dottNum = CardEnum::getCardDott($numstr);      //计算牌点，1－13值 echo "0x". dechex($numstr)."<br>";
            $keyvalues[$numstr] = $dottNum;             //计算牌值位，1－13值
            
            //计算单个值的点数
            $dottval = intval($dottNum);                
            if(isset($numstr) && $dottNum > 10 ){ 
                $jqk_num ++;                            //大于10为花牌
                $dottval = 0 ;
            }
            $resList[$numstr] =  $dottval;              //点数 
        }
        return $resList;
    }

    /**
     * @param array $nums 三公的牌值KEY
     * @param int $dottLevel 牌值的等级
     * @param int $dottMutle 牌值的倍数
     */
    public static function dealSanggLevel($nums = array(),& $dottLevel = 0,& $dottMutle = 1){
        if(!$nums) return false;
        $baseLevels = self::GAME_SANGG_LEVEL;
        $jqk_num = 0;//公仔牌的数目
        $keyvalues = false;
        $keydotts = self::getNiuDottod($nums,$jqk_num,$keyvalues);
        $paiValsArr = array_count_values($keyvalues);//牌值出现次数
        $paiDottsArr = array_count_values($keydotts);
        $max_pval = max($keyvalues);//最大牌值
        //三个牌值相等
        if (sizeof($paiValsArr) ==1){
            if ($max_pval == 3){
                $dottLevel = $baseLevels[12]['level'];     //爆玖
                $dottMutle = $baseLevels[12]['mutle'];
            }else{
                $dottLevel = $baseLevels[11]['level'];     //炸弹
                $dottMutle = $baseLevels[11]['mutle'];
            }
        }else{
            //三公:三个牌值不相等,且点数都为0
            if (sizeof($paiDottsArr) == 1){
                $dottLevel = $baseLevels[10]['level'];
                $dottMutle = $baseLevels[10]['mutle'];
            }else{
                $sumDotts = array_sum($keydotts);//求和
                $numsDotts = $sumDotts % 10;
                $dottLevel = $baseLevels[$numsDotts]['level'];
                $dottMutle = $baseLevels[$numsDotts]['mutle'];
            }
        }
        $maxKeyArr  = array_keys($keyvalues,$max_pval);//最大牌值的键是数组
        $maxKey = max($maxKeyArr);                     //再求一次最大值
        return ["key"=> $dottLevel ,'name'=> $baseLevels[$dottLevel]['name'],"maxCardKey" => $maxKey,"mutl_value"=> $dottMutle];
    }

    /**
     * 比较大小相同等级时；闲赢还是庄赢；
     * @param array $zjCard 庄家牌型
     * @param boolean $xjInfo 闲家牌型
     * @return 1:庄家赢，2：闲家赢
     */

    public static function gatherWhoWin($zjCard,$xianjCard){
        $lastWin = 1 ;
        BaseEnum::Logger("结算XJ： RES ---- ".json_encode($zjCard),'user-login');
        BaseEnum::Logger("结算XJ： RES ---- ".json_encode($xianjCard),'user-login');

        $zjdott = 0;
        $xjdott = 0;
        //取出手牌中点数和花色都是最大牌的值；
        $maxZj = CardEnum::getMaxCardValue($zjCard, $zjdott);       //庄 最大牌
        $maxXj = CardEnum::getMaxCardValue($xianjCard, $xjdott);      //闲 最大牌

        if ($zjdott > 0 && $xjdott > 0 && $zjdott < $xjdott){
            $lastWin = 2;
        }else if($zjdott > 0 && $xjdott > 0 && $zjdott === $xjdott &&  intval($maxZj['hua']) < intval($maxXj['hua'])){
            $lastWin = 2;
        }
        return $lastWin;
    }


    /**
     * 结算逻辑统一处理
     * A: 房间底注
     * M：庄家牌型对应的倍数
     * N：闲家牌型对应的倍数
     * X：庄家抢庄倍数
     * Y：闲家下注倍数
     * 庄家胜利所赢 ＝ A*M*X*Y －抽水
     * 庄家失败所输 ＝ A*N*X*Y
     * 闲家胜利所赢 ＝ A*N*X*Y －抽水
     * 闲家失败所输 ＝ A*M*X*Y
     * 最高 12 * 1 * 抢庄3倍 * 下注倍数(?)  = 2100
     * @param boolean $params
     */
    public static function dealRoomGameSANGG($zjdata = false , $xjdata = false , $fjdata = false,&$returndata = false){
        BaseEnum::Logger("结算QZNN： ING ---- ".json_encode($zjdata),'user-login');
        $zjNiuLevel = isset($zjdata['cardsLevel']) ? $zjdata['cardsLevel'] : 0; //比牌操作；庄家跟每个闲家一一对比；
        $zjcode = isset($zjdata['cards']) ? $zjdata['cards'] : false;                   //庄家的牌数据；
        $zjCardmutl = isset($zjdata['cardsMutle']) ? $zjdata['cardsMutle'] : 1;

        $zjMutle = isset($zjdata['mainMutle']) ? intval($zjdata['mainMutle']) : 1;      //庄家倍数；
        $zjSeatNo = isset($zjdata['seatNo']) ? intval($zjdata['seatNo']) : 0;           //庄家座位号；
        $zjUserId = isset($zjdata['userId']) ? intval($zjdata['userId']) : 0;           //庄家UID；
        $zjOldFee = isset($zjdata['userPoints']) ? floatval($zjdata['userPoints']) : AuthCommon::getLoginUserPoints($zjUserId); //庄家余额；
        $zjBetScore = 0;//总下注，有效下注
        $zjResultMoney = 0;//庄家输赢（包括水钱）
        $zjLastMoney = 0;//真实输赢（去掉水钱）
        $zjWater = 0;//庄家水钱
        $allCards = [$zjSeatNo => $zjcode];
        $moneyArr = [$zjSeatNo=>array()];
        $gameUtype = isset($fjdata["gpKey"]) ? $fjdata["gpKey"] : "";                       //游戏类型
        $fjmoney = isset($fjdata["everyPoints"]) ? floatval($fjdata["everyPoints"]) : 0;    //房间低注金额
        $fjmaxPeop = isset($fjdata["maxPlayer"]) ? intval($fjdata["maxPlayer"]) : 0;    //房间低注金额

        if(!empty($zjdata) && !empty($xjdata) && sizeof($xjdata) >0 && $fjmoney > 0 && $zjSeatNo >= 0){
            foreach ($xjdata as $xjinfo){
                $xjMoney = 0;   //闲家赢的钱
                $xjLevel = isset($xjinfo['cardsLevel']) ? $xjinfo['cardsLevel'] : 0;
                $xjCardMut = isset($xjinfo['cardsMutle']) ? $xjinfo['cardsMutle'] : 1;        //闲家牌型倍数；
                $xjBets = isset($xjinfo['mainMutle']) ? intval($xjinfo['mainMutle']) : 1;      //闲家下注倍数；
                $xianjCard =  isset($xjinfo['cards']) ? $xjinfo['cards'] : false;
                $xjSeatNo = isset($xjinfo['seatNo']) ? intval($xjinfo['seatNo']) : 0;           //闲家家座位号；
                $xjUserId = isset($xjinfo['userId']) ? intval($xjinfo['userId']) : 0;           //闲家座位号；
                $xjOldFee = isset($xjinfo['userPoints']) ? floatval($xjinfo['userPoints']) : AuthCommon::getLoginUserPoints($xjUserId);                                     //闲家余额；
                $allCards[$xjSeatNo] = $xianjCard;

                $lastWin = 1 ;  //通过计算谁家赢：1-庄赢，2-闲赢,
                if(!empty($xianjCard)  && $xjLevel >= 0 && $xjSeatNo >= 0){
                    if($zjNiuLevel > $xjLevel){              //牛相比； 庄赢；
                        $lastWin = 1 ;
                    }else if($zjNiuLevel < $xjLevel){        //牛相比； 闲赢；
                        $lastWin = 2 ;
                    }else if ($zjNiuLevel == $xjLevel) {     //牛相同，比其它； 点数；
                        //三公相同时：比较大小；闲赢还是庄赢；
                        $lastWin = self::gatherWhoWin($zjcode,$xianjCard);
                    }
                    //TODO 计算输赢的钱数据；
                    $zjMoney = CardEnum::countWinMoney($lastWin,$fjmoney,$zjMutle,$zjCardmutl,$xjBets,$xjCardMut,$xjMoney,$zjOldFee,$xjOldFee); // 以小博大(防止输多，赢多操作)

                    //处理庄家
                    $zjBetScore = bcadd($zjBetScore,abs($zjMoney),2);//庄家总投注
                    $zjResultMoney = bcadd($zjResultMoney,$zjMoney,2);//庄家输赢钱
                    //处理闲家
                    $xjWater = 0;
                    $xjLastMoney = $xjMoney;
                    if(isset($xjMoney) && floatval($xjMoney) > 0){
                        $xjWater = bcmul($xjMoney, BaseComm::getSetWaterDott() , 2);    //TODO 最后计算抽水的钱；
                        $xjLastMoney = bcsub($xjMoney, $xjWater , 2);   //TODO 闲家实际输赢，赢分抽水处理
                    }
                    //拼凑闲家结果
                    $moneyArr[$xjSeatNo] = array(
                        "uid"=> $xjUserId,
                        "seatNo"=>$xjSeatNo,
                        "money"=>floatval($xjMoney),
                        "allBetScore"=>abs($xjMoney),                           // 总下注分
                        "cellScore"=>abs($xjMoney),                             // 有效下注分
                        "lastPoints"=>  floatval($xjLastMoney),                 // 实际输赢（除去水钱）
                        "water"=> floatval($xjWater),
                        "level" => $xjLevel,
                        "card_mutle" => $xjCardMut,
                        "zj"=>'闲',
                        "cards"=> $xianjCard
                    );
                }
            }
            //闲家信息没有问题
            if(!empty($moneyArr) && sizeof($moneyArr) > 1 ){
                if (isset($zjResultMoney) && floatval($zjResultMoney) > 0) {
                    $zjWater = bcmul($zjResultMoney, BaseComm::getSetWaterDott() , 2);       //TODO 最后计算抽水的钱；
                    $zjLastMoney = bcsub($zjResultMoney, $zjWater,2);                       //TODO 大于0要抽掉水线
                }else{
                    $zjLastMoney = $zjResultMoney;
                }
                $moneyArr[$zjSeatNo] = array(
                    "uid"=> $zjUserId,
                    "seatNo"=> $zjSeatNo,
                    "money"=>floatval($zjResultMoney),
                    "allBetScore"=> floatval($zjBetScore),                // 总下注分
                    "cellScore"=>floatval($zjBetScore),                                    // 有效下注分
                    "lastPoints"=>  floatval($zjLastMoney),                                 // 实际输赢（除去水钱）
                    "water"=>$zjWater ,
                    "level" => $zjNiuLevel,
                    "card_mutle" => $zjCardmutl,
                    "bet"=>'庄',
                    "cards"=> $zjcode
                );
                //TODO 合计起来，再处理特殊情况 ：庄家钱不赔线的情况；
                //TODO 手牌信息组合；包含信息：总共多少位置，每个玩家的手牌，庄家位置信息；
                $cardValue = BaseComm::conectUserCardsValue($gameUtype,$fjmaxPeop,$allCards,$zjSeatNo);
                $returndata["cardvalues"] = !empty($cardValue) ? $cardValue : ""; //手牌组合数据
            }
        }
        return $moneyArr;
    }
    /**
     * 计算下注最高倍数
     */
    public static function countDeskMaxMutle($totalNum,$zjMuts,$zjPoints,$fjInfo=false){
        $roomEveryPots = isset($fjInfo["everyPoints"]) ? floatval($fjInfo["everyPoints"]) :0 ;  //房间底分
        $minMutl = isset($fjInfo["minMultiple"]) ? intval($fjInfo["minMultiple"]) :0 ;          //房间最高倍
        $maxMutl = isset($fjInfo["maxMultiple"]) ? intval($fjInfo["maxMultiple"]) :0 ;          //房间最高倍
        BaseEnum::Logger("计算倍数参数：everyPoints={$roomEveryPots},minMutl={$minMutl},maxMutl={$maxMutl},totalNum={$totalNum},zjPoints={$zjPoints},zjMutls ={$zjMuts}===","user-login");
        if(!$totalNum || intval($totalNum) < 2 || intval($zjMuts) <= 0  ||!$zjPoints || !$fjInfo || !$roomEveryPots) return 0;
        $lastNum = $totalNum - 1;
        $lastTimes = intval($zjPoints / ($roomEveryPots * 5 * $zjMuts * $lastNum)) ;            //取理论值；5:三公最大的牌型倍数
        if (isset($maxMutl) && $maxMutl > 0 && $lastTimes > $maxMutl) {
            $lastTimes = $maxMutl; //不超过最高倍；
        }
        BaseEnum::Logger("计算倍数结果：lastTimes={$lastTimes},lastNum={$lastNum} ===","user-login");
        return $lastTimes > 0 ? $lastTimes : 0;
    }
}